/*******************************************************************************
 * 版权：北京润尼尔网络科技有限公司，保留所有版权<br>
 * 版本：v1.0.0<br>
 * 文件：CircuitParser.js<br>
 * 日期：2016年9月18日<br>
 * 作者: 王中山<br>
 * 功能：实现电路解算，将电路图解算成spice语句<br>
 * 
 * 修改记录：<br>
 * 日期 描述 更新功能<br>
 ******************************************************************************/

window.makeNamespace(window,"Rainier.UI.V2");

/**
 * 类型名称：Rainier.UI.V2.CircuitParser<br>
 * 类型功能：电路解算器<br>
 */
Rainier.UI.V2.CircuitParser = Rainier.Basic.CompositeObject.extend({
	
	NAME : "Rainier.UI.V2.CircuitParser", 

	/**
	 * 函数名称：Rainier.UI.V2.CircuitParser.init<br>
	 * 函数功能：构造函数<br>
	 * 参数输入：mode：GraphicalModel<br>
	 * 异常信息：无<br>
	 */
    init: function(mode) {
    	this._super();
    	
    	this.spice    	= null;
    	this.rootMode 	= mode;
    	this.context	= mode.context;
    	
    	this.nodeLength = 0;
    	this.unitList 	= [];
    	this.labelList 	= [];
    	this.tstepList  = [];
    	this.bridgeList	= [];
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.GetNodeList<br>
	 * 函数功能：获取结点列表<br>
	 * 参数输入：run : 是否直接运行<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    parse : function (run){
        this.parseMatlab();
    	// if(this.context.menuItemUsedInfo.jointPortUsed && !run){
    	// 	return;
    	// }
    	
    	// this.unitList 	= [];
    	// this.labelList 	= [];
    	// this.getJoinedUnit();
    	// this.parsePortNode();
    	// var sSpice = this.translateUintToSpice();
    	// this.spice = sSpice;
    },

    parseMatlab : function(){
        //获取起始源
        var unitBegin = this.getBegins();

        //按照顺序递归遍历
        var orderUnit = function(unit,index){                
            var nexts = unit.getNextModels();
            index++;
            $.each(nexts,function(j,next){
                next.setIndex(index)
                orderUnit(next,index);
            })
        }

        $.each(unitBegin,function(i,unit){
            var index = 0;
            orderUnit(unit,index);
        });

        //按照序列整理归类
        var unitGroup = {};
        var groupLength = 0;
        var children = this.rootMode.getChildren();
        $.each(children,function(index,child){
            var listIndex = child.listIndex;
            if (listIndex+1 > groupLength) {
                groupLength = listIndex+1;
            }
            if (!unitGroup[listIndex]) {
                unitGroup[listIndex] = [];
            }
            unitGroup[listIndex].push(child);
        });

        //输出解算结果并拼接
        var result = '';
        var imageIndex = 0;
        var addAudio = "";
        for (var i = 0; i < groupLength; i++) {
            var group = unitGroup[i];
            $.each(group,function(index,unit){
                // console.log(i + unit.getProperty().modelProperty.label);
                var label    = unit.getProperty().modelProperty.label;
                var typeName = unit.getProperty().modelProperty.typeName;
                if(typeName === "Add_Audio"){
                    addAudio = unit.tranlateToSpice();
                    return true;
                }
                var matlab = unit.tranlateToSpice();                
                if (matlab && matlab.indexOf('Draw_') >= 0) {
                    matlab += 'print svg_' + label + '.svg\n';
                }
                result += matlab;
            })
        }
        result = addAudio + result;
        result += 'save rainier.mat'
        console.log(result);
        this.spice = result;
        return result;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.getSpice<br>
	 * 函数功能：获取结点列表<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    getSpice : function (){
    	return this.spice;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.GetNodeList<br>
	 * 函数功能：获取结点列表<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    parsePortNode : function(){
    	var _this 			= this;
    	var connectList 	= this.rootMode.getConnections();
    	var children 		= this.rootMode.getChildren();
    	
    	var samePortList	= this.getSamePortList(connectList);
    	var nodeLength 		= this.addNodeIndex(samePortList);
    	
    	this.rootMode.getConnections().each(function(index,conn){
    		conn.changeNodeLabel(true,false);
    	})    	
    	//获取当前节点数(包含0节点)
    	this.nodeLength = nodeLength + 1;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.getSamePortList<br>
	 * 函数功能：获取同组端口数组<br>
	 * 参数输入：connectList ： 连线数组<br>
	 * 参数输出：无<br>
	 * 函数返回：samePortList : 同组端口数组<br>
	 * 异常信息：无<br>
	 */
    getSamePortList : function(connectList){
    	var _this = this;
    	//遍历元件列表，获取同组(即都连接在一起的)端口,获取标签列表
    	var samePortList = [];
    	$.each(_this.unitList,function(index,unit){  
			var inputs   = unit.getInputPorts();
			var outputs  = unit.getOutputPorts();
			var hybrids  = unit.getHybridPorts();
			var ports = [];
			ports = ports.concat(inputs.data).concat(outputs.data).concat(hybrids.data);
			
			$.each(ports,function(i,p){
	    		var inSamePortList = 0;
	    		$.each(samePortList,function(i,same){
	    			if(same.indexOf(p) >= 0){
	    				inSamePortList = 1;
	    				return false;
	    			}
	    		})
	    		if(inSamePortList === 1){
	    			return true;
	    		}
	    		var portList = [];
				_this.getConnectedPort(_this,p,portList,connectList);
				if(portList.indexOf(p) < 0){
					portList.push(p);
				}
				if(portList.length > 1){
					samePortList.push(portList);
				}
				else{
					p.getProperty().modelProperty.node = -1;
				}
			});
    	});
    	return samePortList;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.addNodeIndex<br>
	 * 函数功能：根据同组端口数组添加节点号<br>
	 * 参数输入：samePortList : 同组端口数组<br>
	 * 参数输出：无<br>
	 * 函数返回：nodeLength ：节点数<br>
	 * 异常信息：无<br>
	 */
    addNodeIndex : function(samePortList){       	
    	var _this = this;
    	//查找端口组是否存在接地，并赋相应节点值   
    	var nodeLength = 0; //节点值 ，初始值0
    	$.each(samePortList,function(index,portList){
    		var findGround 		= false;
    		var sameNodeType 	= true;
    		var lastNodeType = '';
    		$.each(portList,function(i,port){
    	    	if(port && port instanceof Rainier.UI.V2.AbstractPortModel){
    	    		var curPortType= port.portType;
    	    		var portParent = port.getParent();
					if(portParent && !findGround){
						var name = portParent.getProperty().modelProperty.typeName;
						if(name && (name.toLowerCase() === 'ground')){
							findGround = true;
						}
					}
					//判断是否存在不同类型的端口 用于添加AD/DA桥
					if(lastNodeType && curPortType && sameNodeType){
						if(lastNodeType !== curPortType){
							sameNodeType = false;
						}
					}				
					if(findGround && !sameNodeType){
						return false;
					}
					lastNodeType = curPortType?curPortType:lastNodeType;//结点不存在端口类型，即undefined
    	    	}    			
    		});
    		if(!findGround){
				nodeLength++;
			}
            var nodeA       = findGround?0:nodeLength;
    		$.each(portList,function(i,port){
    			if(port && port instanceof Rainier.UI.V2.AbstractPortModel){
    				var property 	= port.getProperty().modelProperty;
    				if(!sameNodeType){
        	    		var curPortType	= port.portType;
        	    		if(curPortType == 'D'){
            	    		var portName	= port.getProperty().modelProperty.name;
            	    		var portParent = port.getParent();
        					if(portParent){
        						var label = portParent.getProperty().modelProperty.label;
        						var nodeD = 'd' + label + '.' + portName;
        						var bridge;
        						if(port instanceof Rainier.UI.V2.InputPortModel){
        							bridge = new Rainier.UI.V2.ADBridge(nodeA,nodeD);
        							property.node = nodeD;
                                    property.showNode = nodeA;
        						}
        						else if(port instanceof Rainier.UI.V2.OutputPortModel){
        							bridge = new Rainier.UI.V2.DABridge(nodeD,nodeA);
        							property.node = nodeD;   
                                    property.showNode = nodeA;     							
        						}
        						if(bridge){
        							_this.bridgeList.push(bridge);
        							return true;
        						}
        					}
        	    		}
    				}
    				property.node = nodeA;
    			}
    		})
    	});
    	return nodeLength;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.getConnectedPort<br>
	 * 函数功能：递归遍历端口，获取所有连接端口列表，并删除端口所连连线<br>
	 * 参数输入：_this：Rainier.UI.V2.CircuitParser<br>
	 * 参数输入：port：Rainier.UI.V2.AbstractPortModel<br>
	 * 参数输入：connectList：连线列表<br>
	 * 参数输出：list：同组端口数组<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    getConnectedPort : function(_this,port,list,connectList){

    	var args = arguments;

    	_this.traversalPort(port,function(pt,conn){
    		
			var index = connectList.indexOf(conn);
	        if(index>=0){
	        	connectList.removeElementAt(index);
	        }
	        else{
	        	return;
	        }
	        
	        var sourceport = conn.getSourcePort();
			var targetport = conn.getTargetPort();
			var otherPort = sourceport;
			if(sourceport == port){
				otherPort = targetport;
			}

			if(otherPort){
				if(list.indexOf(otherPort) < 0){
					list.push(otherPort);
					args.callee(_this,otherPort,list,connectList);
					if(otherPort.getParent() instanceof Rainier.UI.V2.JointModel){
						var sourcePort  = otherPort.getParent().getParent().sourcePort;
						if(list.indexOf(sourcePort) < 0){
							list.push(sourcePort);
							args.callee(_this,sourcePort,list,connectList);
						}
					}
				}
			}
			if(conn.hasChildren()){
				var children = conn.getChildren();
				$.each(children,function(index,child){
					if(child instanceof Rainier.UI.V2.JointModel){
						var hybrid  = child.getHybridPorts().get(0);
						if(list.indexOf(hybrid) < 0){
							list.push(hybrid);
							args.callee(_this,hybrid,list,connectList);
						}
					}
				})
			}
    	});
    	
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.traversalPort<br>
	 * 函数功能：遍历端口，获取所有连线，并执行回调函数<br>
	 * 参数输入：port：Rainier.UI.V2.AbstractPortModel<br>
	 * 参数输入：callback：回调函数<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    traversalPort : function(port,callback){
    	
    	if(port && port instanceof Rainier.UI.V2.AbstractPortModel){
    		var incomings = port.getIncomings();
    		var outgoings = port.getOutgoings();
    		
    		incomings.each(function(j,c){
    			callback(port,c);
    		});
    		outgoings.each(function(j,c){
    			callback(port,c);
    		});
    	}
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.getJoinedUnit<br>
	 * 函数功能：获取可结算元件<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    getJoinedUnit : function(){
    	var _this = this;
    	var children = this.rootMode.getChildren();
    	$.each(children,function(index,child){
    		if(child instanceof Rainier.UI.V2.ConnectionModel || child instanceof Rainier.UI.V2.JointModel){
    			return true;
    		}
    		else if(child instanceof Rainier.UI.V2.DeviceModel){
    			_this.unitList.push(child);
    		}
    	});
    	return _this.unitList;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.translateUintToSpice<br>
	 * 函数功能：将元件翻译为Spice语句<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    translateUintToSpice : function(){
    	var _this = this;
    	var unitSpice = '';
    	$.each(this.unitList,function(index,unit){
    		var spice = unit.tranlateToSpice();
    		if(spice){
        		unitSpice += spice;
        		unitSpice += '\n';
        		var step = unit.getTstep();
        		if(step){
        			_this.tstepList.push(step);
        		}
        		
    			var label = _this.getLabelBySpice(spice);
    			if(label){
    				_this.labelList.push(label);
    			}        		
    		}
    	});
    	
    	var adIndex 	= 0;
    	var daIndex 	= 0;
    	var bridgeIndex = 0;
    	$.each(this.bridgeList,function(index,bridge){
    		if(bridge instanceof Rainier.UI.V2.ADBridge){
        		bridgeIndex = ++adIndex;
    		}
    		else{
    			bridgeIndex = ++daIndex;
    		}
    		unitSpice += bridge.formatBridge(bridgeIndex);
    		unitSpice += '\n';
    	})
    	this.bridgeList = [];
    	return unitSpice;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.addControlSpice<br>
	 * 函数功能：添加控制语句<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    addControlSpice : function(sSpice){
    	//todo：添加控制语句，根据不同仿真模式生成相应的控制语句
    	sSpice = '.title\n' + sSpice;
    	var tstep = 0.0001;

    	if(this.tstepList.length > 0){
    		tstep = Math.min.apply(null, this.tstepList)/100;
        	sSpice += '.tran '+tstep+' 1e30  0  '+tstep*2+' \n	.end';
    	}
    	else{
        	sSpice += '.tran '+tstep+' 1e30  0  '+tstep*10+' \n	.end';
    	}
    	this.tstepList = [];
    	return sSpice;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CircuitParser.computeMinAndMaxStep<br>
	 * 函数功能：计算最大步长和最小步长<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    computeMinAndMaxStep : function(){
    	var step    = {};
    	this.parse(true);
    	step.minStep = 0.0001;
    	step.maxStep = step.minStep * 10;
    	if(this.tstepList.length > 0){
    		step.minStep = Math.min.apply(null, this.tstepList)/100;
    		step.maxStep = step.minStep * 2;
    	}
        this.tstepList = [];
    	return step;
    },
    
    /**
	 * 函数名称：<br>
	 * 函数功能：<br>
	 * 参数输入：<br>
	 * 参数输出：<br>
	 * 函数返回：<br>
	 * 异常信息：<br>
	 */
    getLabelBySpice : function(sSpice){
    	var spice = sSpice.replace(/(^\s*)/g, ""); 
    	var index = spice.indexOf(' ');
    	return spice.substr(0,index);
    },
    
    /**
	 * 函数名称：<br>
	 * 函数功能：<br>
	 * 参数输入：<br>
	 * 参数输出：<br>
	 * 函数返回：<br>
	 * 异常信息：<br>
	 */
    makeSpice : function(sSpice){
    	var objValues = this.context.experimentCfg;
    	if(!objValues){
    		throw new Error("您的执行顺序有问题，请检查程序，排除错误");
    	}
    	 
    	var spiceSentence = '.title\n' + sSpice;
		
    	spiceSentence += ".options ";
		var arr = ['ABSTOL','VNTOL','RELTOL','ITL4'];
		$.each(arr,function(index,key){
			if(objValues[key])
				spiceSentence += key + "=" + objValues[key] + ' ';
		});
		
		spiceSentence += "\n.tran ";
		var arr1 = ["#4","#2","#3","#1"];
		$.each(arr1,function(index,key){
			if(objValues[key]){
				spiceSentence += objValues[key] + ' ';
				if(key === '#2'){
					spiceSentence += '0 ';
				}
			}
		});
		
		spiceSentence += '\n.end';
		return spiceSentence;
    },

    getBegins : function(){
        var units = [];
        var children = this.rootMode.getChildren();
        $.each(children,function(index,child){
            if(child instanceof Rainier.UI.V2.ConnectionModel || child instanceof Rainier.UI.V2.JointModel){
                return true;
            }
            else if(child instanceof Rainier.UI.V2.DeviceModel){
                var inputs = child.getInConns();
                var outputs = child.getOutConns();

                if (!inputs.getSize() && outputs.getSize()) {
                    units.push(child);
                }
            }
        });
        return units;
    },
});